// Copyright (c) Microsoft Corporation. 
// Licensed under the MIT license.

#pragma once

#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"

class AStandInMeshActor;
class AActor;
class ULevel;
class UPackage;

/**
 * @brief Utilities for Create/Merging/Moving/Generating AStandinMeshActor
 */
class IStandinUtilitiesModule : public IModuleInterface
{

public:
	
	/**
	 * @brief Get the StandinUtilitiesModule.
	 * @return Returns a reference to IStandinUtilitiesModule.
	*/
	static inline IStandinUtilitiesModule& Get()
	{
		return FModuleManager::LoadModuleChecked< IStandinUtilitiesModule >("StandinUtilities");
	}

	/**
	 * @brief Check if the module is loaded.
	 * @return Returns true if module is loaded.
	*/
	static inline bool IsAvailable()
	{
		return FModuleManager::Get().IsModuleLoaded("StandinUtilities");
	}

	/**
	 * @brief Generate a Standin Mesh.
	 * @param StandinActors List of StandInMeshActors to generate.
	 * @param OverridePackageNames Optional parameter to override package names per standin mesh. Mainly used by "Save to package" feature. 
	*/
	virtual void GenerateStandinMeshes(const TArray<AStandInMeshActor*>& StandinActors, const TMap<AStandInMeshActor*, FString>& OverridePackageNames = {}) = 0;

	/**
	 * @brief Build Standin Mesh Actors.
	 * @param bRebuild If set to true a build will be forced.
	*/
	virtual void BuildStandinMeshActors(bool bRebuild) = 0;

	/**
	 * @brief GroupUnderStandinActor
	*/
	virtual void GroupUnderStandinActor() = 0;

	/**
	 * @brief Add a list of actors to a AStandIMeshActor.
	 * @param InStandinActor StandinMesh Actor.
	 * @param InSelectedActors  List of actors to add.
	*/
	virtual void AddActorsToStandinActor(AStandInMeshActor* InStandinActor, const TArray<AActor*>& InSelectedActors) = 0;

	/**
	 * @brief Remove a list of actors from a AStandInMeshActor.
	 * @param InStandinActor StandinMesh Actor.
	 * @param InSelectedActors List of actors to remove.
	*/
	virtual void RemoveActorsFromStandinActor(AStandInMeshActor* InStandinActor, const TArray<AActor*>& InSelectedActors) = 0;

	/**
	 * @brief A method that return true if actor has valid static mesh components and can be used for standin.
	 * @param InActor The Actor to check if can be bumped to a StandinMeshActor
	 * @return Returns true if a valid standin can be created for actor.
	*/
	virtual bool IsActorValidForStandinInclusion(AActor* InActor) = 0;

	/**
	 * @brief  Creates a new AStandinMeshActor replacing actors.
	 * @param InActors List of actors to be replaced. 
	 * @return Returns a new AStandInMeshActor.
	*/
	virtual AStandInMeshActor* CreateStandinMeshActor(const TArray<AActor*>& InActors) = 0;

	/**
	 * @brief Check to see if actors belong in the same level.
	 * @param InActors List of actors to check.
	 * @return Returns true if actors belong to save presistent level else false.
	*/
	virtual const bool AreActorsInSamePersistingLevel(const TArray<AActor*>& InActors) = 0;
		
	/**
	 * @brief Merge StandinMeshAcors
	 * @param ToActor AStandinMeshActor to merge into.
	 * @param FromActor AStandinMeshActor to merge from.
	*/
	virtual void MergeStandinActors(AStandInMeshActor* ToActor, AStandInMeshActor* FromActor) = 0;

	/**
	 * @brief Add Actor to StandinActor.
	 * @param InActor Actor to add to StandinMeshActor.
	 * @param InParentActor The StandinMeshActor.
	*/
	virtual void AddActorToStandinActor(AActor* InActor, AStandInMeshActor* InParentActor) = 0;

	/**
	 * @brief Remove and Actor from StandinActor if it belongs to a standin actor.
	 * @param InActor The actor to remove.
	 * @return Returns true if sucessful else false.
	*/
	virtual const bool RemoveActorFromStandinActor(AActor* InActor) = 0;

	/**
	 * @brief Gets the Standin Actor if the Actor has any.
	 * @param InActor  Actor to check if it has a Standin.
	 * @return  Returns AStandInMeshActor if one exist else nullptr.
	*/
	virtual AStandInMeshActor* GetStandinActor(AActor* InActor) = 0;

	/**
	 * @brief Destory the StandinMeshActor.
	 * @param InActor The StandinMeshActor to destory.
	 * @return Returns true if sucessfull else false.
	*/
	virtual bool DestroyStandinActor(AStandInMeshActor* InActor) = 0;

	/** 
	 * @brief Method to check if the actors in a list are already being replaced or not.
	 *  @param InActors 'InActors' List of Actors to check.
	 *  @return Returns true if all are already being replaced else false.
	*/
	virtual const bool AreActorsAlreadyBeingReplaced(const TArray<AActor*>& InActors) = 0;

	/** 
	 * @brief Gets a list of StandInMeshActor from the current world context.
	 * @param OutActors 'OutActors' List of StandinMeshActors retrieved
	*/
	virtual void GetStandinActors(TArray<AStandInMeshActor*>& OutActors) = 0;


	/**
	 * @brief Save packages for standins.
	*/
	virtual void SavePackagesForStandins() = 0;


	/**
	 *  @brief Method to get a list of packages that are generated as part of Standin build process and require saving. 
	 *  @param Level 'Level' Level where to look for standins.
	 *  @param PackagesToSave 'PackagesToSave' list of packages that require saving.
	 *  @param PreviousLevelName 'PreviousLevelName' Name of the previous level if renamed or moved.
	 *  @return Returns true if all are already being replaced else false.
	*/
	virtual void GetListOfPackagesToSaveForStandins(const ULevel* Level, TSet<UPackage*>& PackagesToSave, const FString& PreviousLevelName = "") = 0;

};

